The resolution table:
~~~~~~~~~~~~~~~~~~~~~
SHOCK2.EXE		0x2af768
THIEF.EXE		0x213a78
THIEF.EXE		0x213c70
THIEF.EXE (Gold)	0x213b40
THIEF2.EXE		0x277fb0
DROMED.EXE (SS2)	0x43e5c8
DROMED.EXE (T1)		0x392ef8
DROMED.EXE (T2)		0x3e9120

The resolution table is located at this offsets.
There are 87 entries and each resolution takes up 12bytes.
0	counter (0-86)
1-3	zero (for almost all resolutions)
4-5	x
6-7	y
8	color depth (4,8,15,16,24,32)
9	needs to be one for a resolution to work
	it is zero for 4,24,32 - one for 8,15,16
10-11	zero

The interesting bytes are 4-7, obviously. You can modify the table as you wish but you might want to stick to 16bit modes.
A note on 9: If this is zero the resolution will not work. Setting it to one for 32bit modes does not magically make them work. There is additional code in place that keeps the game from letting you select 32bit and even if that is changed it will not work correctly: Textures are wrong, the interface is totally fucked and it just crashes sooner or later, ...usually sooner.



Making the resolutions appear in the menu:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			in memory	in file
SHOCK2.EXE		0x569fb0	0x1693b0
THIEF.EXE		0x51D084	0x11c484
THIEF.EXE		0x51CFA4	0x11c3a4
THIEF.EXE (Gold)	0x51D114	0x11c514
THIEF2.EXE		0x565983	0x165983
DROMED.EXE (SS2)	0x616990	0x215d90
DROMED.EXE (T1)		0x598AB4	0x197eb4
DROMED.EXE (T2)		0x5FD8D3	0x1fd8d3

As you might know System Shock 2 does not allow you to select any mode with a vertical resolution larger than 768 through its menu although it does natively support 1600x1200 if you edit cam.cfg. This is easy. Just go to the offset and change the value from 768 to your vertical resolution. If you just wanted to play in a previously unsupported 4:3 resolution then you are done here. But if you want widescreen you'll notice that the game just doesn't look right yet, so read on.



The current resolution
~~~~~~~~~~~~~~~~~~~~~~
is stored at:
			x		y
SHOCK2.EXE		0x77E848	0x77E84C
THIEF.EXE		0x745D36	0x745D3A
THIEF.EXE		0x745D36	0x745D3A
THIEF.EXE (Gold)	0x745DF6	0x745DFA
THIEF2.EXE		0x7D3036	0x7D303A
DROMED.EXE (SS2)	0xB64978	0xB6497C
DROMED.EXE (T1)		0xA9CB90	0xA9CB94
DROMED.EXE (T2)		0xADEEB0	0xADEEB2

We will need this later on.



The field of view:
~~~~~~~~~~~~~~~~~~
The Dark Engine does not natively support widescreen resolutions. In fact even the support for 1280x1024 (which is a 5:4 mode) is poor. The field of view is always fitting for 4:3 which means that in 5:4 the image will appear stretched out vertically while in widescreen it will be stretched out horizontally. Previous versions tried to correct this discrepancy by scaling outwards on the x-axis. This, however, caused an issue with objects ploping into view at the edges of the screen. The proper solution is to zoom out on the whole scene an then later scale inwards on the y-axis. To accomplish this we have to interrupt the games calculation in two different places and write our own function that corrects these calculations by taking the widescreen aspect ratio into account.



Interrupting the fov calculation:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			in memory	in file
SHOCK2.EXE		0x434462	0x033862
			0x5D3328	0x1d2728
THIEF.EXE		0x433569	0x032969
			0x5630C8	0x1624c8
THIEF.EXE		0x4336A9	0x032aa9
			0x563048	0x162448
THIEF.EXE (Gold)	0x433599	0x032999
			0x563038	0x162438
THIEF2.EXE		0x4393EF	0x0393ef
			0x5ABE28	0x1abe28
DROMED.EXE (SS2)	0x441E6C	0x04126c
			0x68B038	0x28a438
DROMED.EXE (T1)		0x440353	0x03f753
			0x60EF78	0x20e378
DROMED.EXE (T2)		0x4478F9	0x0478f9
			0x64EC08	0x24ec08

As said above we have to intervene in two places. In both cases this can be done by overwriting a fmul instruction with a call to a custom function (which will be added in the next step). In the first location there is an instruction that would multiply the value on top of the floating point stack with the zoom factor (in DromEd this is equivalent to whatever set_3d_zoom is set to, in games it is always one). We will use this to zoom out of the whole scene. In the second location there is a multiplication by 1/65536 (don't ask) which will be modified to scale in vertically.

SHOCK2.EXE
434462		D80D 9C926600		FMUL DWORD PTR DS:[66929C]
-->
434462		90			NOP
434463		E8 28351F00		CALL SHOCK2.00627990


SHOCK2.EXE
5D3328		D80D 68806500		FMUL DWORD PTR DS:[658068]
-->
5D3328		90			NOP
5D3329		E8 76460500		CALL SHOCK2.006279A4



Correcting the calculation:
~~~~~~~~~~~~~~~~~~~~~~~~~~~
			in memory	in file
SHOCK2.EXE		0x627990	0x226d90
THIEF.EXE		0x5B3490	0x1b2890
THIEF.EXE		0x5B3620	0x1b2a20
THIEF.EXE (Gold)	0x5B3560	0x1b2960
THIEF2.EXE		0x5FDAF0	0x1fdaf0
DROMED.EXE (SS2)	0x6EA690	0x2e9a90
DROMED.EXE (T1)		0x669680	0x268a80
DROMED.EXE (T2)		0x6AB9F0	0x2ab9f0


Now we have to introduce a factor that measures how much the current aspect ratio differs from 4:3. This factor can be calculated as:

fov_correction  =  4/3 * y/x
(This is approx. 0.833 for 16:10 and 0.75 for 16:9)

Let's add another feature: In DromEd the user can modify the overall fov by specifying set_3d_zoom, but in the games the fov is immutable. To allow changing the fov we accept a fov_modification value in percent. In order to do this and the zooming mentioned above one has to calculate

zoom * fov_correction * 100/fov_modification  =  zoom * 133.33 / fov_modification * y  / x

Now that the image is zoomed out we have to scale vertically to compensate. We calculate

1/65536 * fov_correction  =  2.03e-5 * y / x

OK, so now that we know what to do we go to the location that gets called by the code we inserted above and write our own function to implemet all this. See below for an example of how this might look in System Shock 2: It has two different entry points. The first one at 6EA690 starts off by loading the zoom factor, multiplies by 133.33 and divides by fov_modification (100 in this example). Then it jumps to the multiplication with y and division by x. After that it runs the multiplication on the floating point stack, cleans up and returns to the normal path of execution. The second entry is at 6EA6A4 and begins by loading 2.03e-5, the rest is the same as the end of entry one.

SHOCK2.EXE
627990	$	D905 9C926600		FLD DWORD PTR DS:[66929C]
627996		DC0D BB796200		FMUL QWORD PTR DS:[6279BB]
62799C		DE35 C3796200		FIDIV WORD PTR DS:[6279C3]
6279A2	   V	EB 06			JMP SHORT SHOCK2.006279AA
6279A4	$	DD05 C5796200		FLD QWORD PTR DS:[6279C5]
6279AA	    >	DE0D 4CE87700		FIMUL WORD PTR DS:[77E84C]
6279B0		DE35 48E87700		FIDIV WORD PTR DS:[77E848]
6279B6		D8C9			FMUL ST,ST(1)
6279B8		DDC1			FFREE ST(1)
6279BA		C3			RETN
6279BB		A9AAAAAAAAAA6040	DQ FLOAT 133.3333333333333
6279C3		6400			DW 0064
6279C5		4B5555555555F53E	DQ FLOAT 2.034505208333330e-05



Inventory:
~~~~~~~~~~
			in memory	in file
THIEF.EXE		0x5191D2	0x1185d2
THIEF.EXE		0x5190F2	0x1184f2
THIEF.EXE (Gold)	0x519262	0x118662
THIEF2.EXE		0x561312	0x161312
DROMED.EXE (T1)		0x594BB2	0x193fb2
DROMED.EXE (T2)		0x5F9112	0x1f9112

In System Shock 2 the 3D view for inventory items can always take up the same amount of pixels. In Thief however it is resolution dependant, hence the following problem is specific to Thief games. The area for the inventory items is x/5 by y/5 pixels. With the widescreen mod this area will obviously be wider than before. The item is rendered in a larger size and thus might get cut off at the top and bottom. To counter this we have to decrease the width of the item area again.
The size is calculated by multiplying x (or y) with 20 and then dividing by 100 using integer reciprocals. Here is a code excerpt without the division. ESI+8 holds x, ESI+A holds y and the other two pointers both point to 20.

THIEF2.EXE
561312		0FBF4E 08		MOVSX ECX,WORD PTR DS:[ESI+8]
561316		0FAF0D 241D6700		IMUL ECX,DWORD PTR DS:[671D24]
56131D		F7E9			IMUL ECX
56131F		0FBF4E 0A		MOVSX ECX,WORD PTR DS:[ESI+A]
561323		0FAF0D 281D6700		IMUL ECX,DWORD PTR DS:[671D28]

Instead of x * 20 we want to calculate:
x * 20 * fov_correction = x * 20 * 4/3 * y/x = y * 20 * 4/3

Hence we change ESI+8 to ESI+A, which is y and multiply the value at 671D24 with 4/3. This fix is not perfectly accurate due to rounding error but the difference should be hardly noticeable.
